home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir31 / tnypl211.zip / MODPL16.ASM < prev    next >
Assembly Source File  |  1994-06-21  |  63KB  |  2,116 lines

  1. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  2. ;           16-bit Tiny MOD Player for Borland C++ 3.1 C compiler
  3. ;                      Version 2.11a  June 15th, 1994
  4. ;
  5. ;                      Copyright 1993,94 Carlos Hasan
  6. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  7.  
  8. ideal
  9. model   large,c
  10. p386
  11. smart
  12.  
  13. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  14. ; EQUATES AND PUBLICS
  15. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  16.  
  17. MAXVOICES = 8                           ; number of voices
  18. DMABUFLEN = 1024                        ; DMA buffer length (multiple of 64)
  19. VOLBUFLEN = 66*256                      ; volume table length
  20. MIXBUFLEN = DMABUFLEN+2048              ; mixing/boosting buffer length
  21. TIMERRATE = 17000                       ; timer interrupt rate in ticks
  22.  
  23. global  MODPlayModule:proc
  24. global  MODStopModule:proc
  25. global  MODPlaySample:proc
  26. global  MODStopSample:proc
  27. global  MODSetPeriod:proc
  28. global  MODSetVolume:proc
  29. global  MODSetMusicVolume:proc
  30. global  MODSetSampleVolume:proc
  31. global  MODDetectCard:proc
  32. global  MODPoll:proc
  33.  
  34. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  35. ; STRUCTURES
  36. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  37.  
  38. struc   module                          ; module structure
  39.   numtracks     dw      ?               ; number of tracks
  40.   orderlen      dw      ?               ; order length
  41.   orders        db      128 dup (?)     ; order list
  42.   patterns      dd      128 dup (?)     ; pattern addresses
  43.   sampptr       dd      32 dup (?)      ; sample start addresses
  44.   sampend       dd      32 dup (?)      ; sample end addresses
  45.   samploop      dd      32 dup (?)      ; sample loop point addresses
  46.   sampvolume    db      32 dup (?)      ; sample default volumes
  47. ends    module
  48.  
  49. struc   sample                          ; sample structure
  50.   period        dw      ?               ; default period
  51.   volume        dw      ?               ; default volume
  52.   datalen       dd      ?               ; sample data length
  53.   dataptr       dd      ?               ; sample data address
  54. ends    sample
  55.  
  56. struc   track                           ; track structure
  57.   note          dw      ?               ; note index
  58.   period        dw      ?               ; period value
  59.   inst          db      ?               ; instrument
  60.   volume        db      ?               ; volume
  61.   effect        dw      ?               ; effect
  62.   destperiod    dw      ?               ; toneporta wanted period
  63.   tonespeed     db      ?               ; toneporta speed
  64.   vibparm       db      ?               ; vibrato depth/rate
  65.   vibpos        db      ?               ; vibrato wave position
  66.   tremparm      db      ?               ; tremolo depth/rate
  67.   trempos       db      ?               ; tremolo wave position
  68.                 db      ?               ; alignment
  69.   arptable      dw      3 dup (?)       ; arpeggio periods
  70. ends    track
  71.  
  72. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  73. ; DATA
  74. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  75.  
  76. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  77. ; Module Player data
  78. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  79. udataseg
  80.  
  81. moduleptr       dd      ?               ; current module address
  82. pattptr         dd      ?               ; current playing pattern address
  83. orderpos        db      ?               ; order position
  84. orderlen        db      ?               ; order length
  85. pattrow         db      ?               ; pattern row
  86. tempo           db      ?               ; tempo
  87. tempocount      db      ?               ; tempo counter
  88. bpm             db      ?               ; beats per minute
  89. musicvolume     db      ?               ; music channels volume
  90. samplevolume    db      ?               ; sample channels volume
  91. numtracks       dw      ?               ; number of tracks
  92. tracks          track   MAXVOICES dup (?)
  93.  
  94. pitchtable      dd      3425 dup (?)    ; period to pitch table
  95.  
  96. ; Amiga period table
  97. dataseg
  98.  
  99. periodtable     dw      0
  100.                 dw      3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920,1812
  101.                 dw      1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906
  102.                 dw      856,808,762,720,678,640,604,570,538,508,480,453
  103.                 dw      428,404,381,360,339,320,302,285,269,254,240,226
  104.                 dw      214,202,190,180,170,160,151,143,135,127,120,113
  105.                 dw      107,101,95,90,85,80,75,71,67,63,60,56
  106.                 dw      53,50,47,45,42,40,37,35,33,31,30,28
  107.  
  108. ; Sinus wave table
  109.  
  110. sintable        db      0,25,50,74,98,120,142,162,180,197,212,225
  111.                 db      236,244,250,254,255,254,250,244,236,225
  112.                 db      212,197,180,162,142,120,98,74,50,25
  113.  
  114. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  115. ; Sound Blaster driver data
  116. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  117. udataseg
  118.  
  119. ; Voices programmable parameters
  120.  
  121. voicepos        dd      MAXVOICES dup (?)
  122. voiceend        dd      MAXVOICES dup (?)
  123. voiceloop       dd      MAXVOICES dup (?)
  124. voicefrac       dd      MAXVOICES dup (?)
  125. voicepitch      dd      MAXVOICES dup (?)
  126. voicevolume     dd      MAXVOICES dup (?)
  127.  
  128. ; Internal driver data
  129. dataseg
  130.  
  131. mixbuffer       dw      ?               ; mixing buffer address
  132. boosttable      dw      ?               ; boosting table address
  133. voltable        dw      ?               ; volume table address
  134. numvoices       dw      ?               ; number of active voices
  135. mixfreq         dw      ?               ; playback frequency
  136. ioaddr          dw      ?               ; card I/O port address
  137. irqnum          db      ?               ; card IRQ level
  138. drqnum          db      ?               ; card DMA channel
  139. timerproc       dw      ?               ; timer callback address
  140. timeracc        dw      ?               ; timer callback accumulator
  141. timerspeed      dw      ?               ; timer callback speed
  142. bufsel          dw      ?               ; DOS memory block selector
  143. bufptr          dw      ?               ; DMA buffer address
  144. bufoff          dw      ?               ; double buffer offset
  145. oldirqoff       dw      ?               ; old IRQ vector address
  146. oldirqsel       dw      ?
  147. oldtimeroff     dw      ?               ; old timer IRQ0 vector address
  148. oldtimersel     dw      ?
  149. oldtimeracc     dw      ?               ; old timer accumulator
  150. manualmode      db      ?               ; timer/manual polling mode
  151. playing         db      0               ; playing/stopped status
  152.  
  153. ufardata fardataseg
  154.         db      DMABUFLEN+VOLBUFLEN+MIXBUFLEN+15 dup (?)
  155.  
  156. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  157. ; CODE
  158. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  159. codeseg
  160.  
  161. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  162. ; Copyright Strings
  163. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  164.  
  165. db      '16-bit Tiny MOD Player V2.11 Copyright 1993,94 Carlos Hasan',0
  166. db      'Compiled on: ',??date,' ',??time,0
  167.  
  168. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  169. ; Module Player stuff
  170. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  171.  
  172. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  173. ; MODPlayModule - start playing a music module
  174. ; In:
  175. ;  Song  = module address
  176. ;  Chans = number of channels
  177. ;  Rate  = playback rate
  178. ;  Port  = port address
  179. ;  irq   = irq number
  180. ;  dma   = dma channel
  181. ;  mode  = polling mode
  182. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  183. proc    MODPlayModule Song:dword,Chans:byte,Rate:word,Port:word,IRQ:byte,DRQ:byte,Mode:byte
  184.         pushad
  185.         push    es
  186.  
  187. ; setup the music module address
  188.  
  189.         les     si,[Song]
  190.         mov     [word low moduleptr],si
  191.         mov     [word high moduleptr],es
  192.  
  193. ; setup the sound card driver
  194.  
  195.         mov     ax,[Rate]
  196.         mov     bl,[Chans]
  197.         mov     dx,[Port]
  198.         mov     cl,[IRQ]
  199.         mov     ch,[DRQ]
  200.         mov     bh,[Mode]
  201.         call    mixinit
  202.         jc      playmoduled0
  203.  
  204. ; build the period to pitch table (16.16 fixed point values)
  205.  
  206.         movzx   ebx,ax
  207.         mov     eax,8363*428
  208.         xor     edx,edx
  209.         shld    edx,eax,16
  210.         shl     eax,16
  211.         div     ebx
  212.         mov     esi,eax
  213.         lea     di,[pitchtable]
  214.         mov     cx,3425
  215.         xor     bx,bx
  216. playmodulel0:
  217.         inc     bx
  218.         xor     edx,edx
  219.         mov     eax,esi
  220.         div     ebx
  221.         mov     [di],eax
  222.         add     di,4
  223.         loop    playmodulel0
  224.  
  225. ; setup global volumes for music and sample channels
  226.  
  227.         mov     [musicvolume],255
  228.         mov     [samplevolume],255
  229.  
  230. ; clear the module player track structures
  231.  
  232.         push    es
  233.         mov     ax,ds
  234.         mov     es,ax
  235.         cld
  236.         lea     di,[tracks]
  237.         mov     cx,MAXVOICES*(size track)
  238.         xor     al,al
  239.         rep     stosb
  240.         pop     es
  241.  
  242. ; check if there is a module to playback
  243.  
  244.         xor     ax,ax
  245.         mov     [numtracks],ax
  246.  
  247.         mov     si,[word low moduleptr]
  248.         or      si,[word high moduleptr]
  249.         test    si,si
  250.         clc
  251.         je      playmoduled0
  252.  
  253. ; setup player interpreter variables
  254.  
  255.         les     si,[moduleptr]
  256.         mov     ax,[es:si+module.orderlen]
  257.         mov     [orderlen],al
  258.         mov     ax,[es:si+module.numtracks]
  259.         mov     [numtracks],ax
  260.         mov     [tempo],6
  261.         mov     [bpm],125
  262.         mov     [orderpos],0
  263.         mov     [tempocount],0
  264.         mov     [pattrow],40h
  265.  
  266. ; setup the player callback timer routine
  267.  
  268.         lea     dx,[pollmodule]
  269.         call    mixsettimerproc
  270.         mov     dl,[bpm]
  271.         call    mixstarttimer
  272.         clc
  273.  
  274. playmoduled0:
  275.         pop     es
  276.         popad
  277.         sbb     ax,ax
  278.         ret
  279. endp    MODPlayModule
  280.  
  281. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  282. ; MODStopModule - shut down the music system
  283. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  284. proc    MODStopModule
  285.         pushad
  286.         call    mixstoptimer            ; stop the timer callback
  287.         call    mixdone                 ; shutdown the SB stuff
  288.         popad
  289.         ret
  290. endp    MODStopModule
  291.  
  292. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  293. ; MODPoll - polls the music system in manual mode
  294. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  295. proc    MODPoll
  296.         pushad
  297.         cmp     [manualmode],0          ; call the polling routine only
  298.         je      modpolld0               ; if we are using the manual
  299.         cmp     [playing],0             ; polling mode (and if the driver
  300.         je      modpolld0               ; is active).
  301.         call    mixpoll
  302. modpolld0:
  303.         popad
  304.         ret
  305. endp    MODPoll
  306.  
  307. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  308. ; MODPlaySample - play sample instrument
  309. ; In:
  310. ;  voice  = voice number
  311. ;  sample = sample address
  312. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  313. proc    MODPlaySample Voice:word,SamplePtr:dword
  314.         pushad
  315.         push    es
  316.         cli
  317.  
  318. ; get the voice number and track address
  319.  
  320.         movzx   ebx,[Voice]
  321.         les     di,[SamplePtr]
  322.         mov     si,bx
  323.         imul    si,size track
  324.  
  325. ; set the voice pitch value
  326.  
  327.         movzx   eax,[es:di+sample.period]
  328.         mov     eax,[4*eax+pitchtable]
  329.         mov     [4*ebx+voicepitch],eax
  330.  
  331. ; set the voice sample parameters
  332.  
  333.         mov     eax,[es:di+sample.dataptr]
  334.         mov     [4*ebx+voicepos],eax
  335.         add     eax,[es:di+sample.datalen]
  336.         mov     [word low 4*ebx+voiceend],ax
  337.         mov     [word low 4*ebx+voiceloop],ax
  338.  
  339. ; set the voice and track volumes
  340.  
  341.         mov     ax,[es:di+sample.volume]
  342.         mov     [si+tracks.volume],al
  343.         mul     [samplevolume]
  344.         mov     [byte 4*ebx+voicevolume],ah
  345.  
  346.         sti
  347.         pop     es
  348.         popad
  349.         ret
  350. endp    MODPlaySample
  351.  
  352. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  353. ; MODStopSample - stop the playing sample
  354. ; In:
  355. ;  voice = voice number
  356. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  357. proc    MODStopSample Voice:word
  358.         pushad
  359.         cli
  360.  
  361. ; get the voice number
  362.  
  363.         movzx   ebx,[Voice]
  364.         xor     eax,eax
  365.  
  366. ; clear the voice sample parameters
  367.  
  368.         mov     [4*ebx+voicepos],eax
  369.         mov     [word low 4*ebx+voiceend],ax
  370.         mov     [word low 4*ebx+voiceloop],ax
  371.  
  372.         sti
  373.         popad
  374.         ret
  375. endp    MODStopSample
  376.  
  377. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  378. ; MODSetPeriod -  set the voice period value
  379. ; In:
  380. ;  voice = voice number
  381. ;  period = period value (113-856)
  382. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  383. proc    MODSetPeriod Voice:word,Period:word
  384.         pushad
  385.         cli
  386.  
  387. ; get the voice number and period value
  388.  
  389.         movzx   ebx,[Voice]
  390.         movzx   eax,[Period]
  391.  
  392. ; set the voice pitch value
  393.  
  394.         mov     eax,[4*eax+pitchtable]
  395.         mov     [4*ebx+voicepitch],eax
  396.  
  397.         sti
  398.         popad
  399.         ret
  400. endp    MODSetPeriod
  401.  
  402. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  403. ; MODSetVolume -  set the voice volume level
  404. ; In:
  405. ;  voice = voice number
  406. ;  volume = volume level (0-64)
  407. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  408. proc    MODSetVolume Voice:word,Volume:word
  409.         pushad
  410.         cli
  411.  
  412. ; get the voice number and track address
  413.  
  414.         movzx   ebx,[Voice]
  415.         mov     ax,[Volume]
  416.         mov     si,bx
  417.         imul    si,size track
  418.  
  419. ; set the voice and track volume
  420.  
  421.         mov     [si+tracks.volume],al
  422.         mul     [samplevolume]
  423.         mov     [byte 4*ebx+voicevolume],ah
  424.  
  425.         sti
  426.         popad
  427.         ret
  428. endp    MODSetVolume
  429.  
  430. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  431. ; MODSetMusicVolume - set the global music volume
  432. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  433. proc    MODSetMusicVolume Volume:word
  434.         pushad
  435.         cli
  436.  
  437. ; set new music volume
  438.  
  439.         mov     ax,[Volume]
  440.         mov     [musicvolume],al
  441.  
  442. ; update all the music voices
  443.  
  444.         lea     si,[tracks]
  445.         xor     ebx,ebx
  446. setmusicvolumel0:
  447.         mov     al,[si+track.volume]
  448.         mul     [musicvolume]
  449.         mov     [byte 4*ebx+voicevolume],ah
  450.         add     si,size track
  451.         inc     bx
  452.         cmp     bx,[numtracks]
  453.         jb      setmusicvolumel0
  454.  
  455.         sti
  456.         popad
  457.         ret
  458. endp    MODSetMusicVolume
  459.  
  460. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  461. ; MODSetSampleVolume - set the global sample volume
  462. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  463. proc    MODSetSampleVolume Volume:word
  464.         pushad
  465.         cli
  466.  
  467. ; set the sample volume
  468.  
  469.         mov     ax,[Volume]
  470.         mov     [samplevolume],al
  471.  
  472. ; update all the sample voices
  473.  
  474.         lea     si,[tracks]
  475.         xor     ebx,ebx
  476. setsamplevolumel0:
  477.         cmp     bx,[numtracks]
  478.         jb      setsamplevolumef0
  479.         mov     al,[si+track.volume]
  480.         mul     [samplevolume]
  481.         mov     [byte 4*ebx+voicevolume],ah
  482. setsamplevolumef0:
  483.         add     si,size track
  484.         inc     bx
  485.         cmp     bx,MAXVOICES
  486.         jb      setsamplevolumel0
  487.  
  488.         sti
  489.         popad
  490.         ret
  491. endp    MODSetSampleVolume
  492.  
  493. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  494. ; MODDetectCard - detect the Sound Blaster configuration
  495. ; Out:
  496. ;  Port = I/O Port
  497. ;  IRQ = IRQ level
  498. ;  DRQ = DMA channel
  499. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  500. proc    MODDetectCard Port:dword,IRQ:dword,DRQ:dword
  501.         pushad
  502.         push    es
  503.  
  504. ; call the lowlevel autodetection routine
  505.  
  506.         call    mixdetect
  507.  
  508. ; set the parameters in the user variables
  509.  
  510.         les     di,[Port]
  511.         mov     [es:di],dx
  512.         les     di,[IRQ]
  513.         mov     [es:di],cl
  514.         les     di,[DRQ]
  515.         mov     [es:di],ch
  516.  
  517.         pop     es
  518.         popad
  519.         sbb     ax,ax
  520.         ret
  521. endp    MODDetectCard
  522.  
  523. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  524. ; pollmodule - polls the module player
  525. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  526. pollmodule:
  527.         pushad
  528.         push    es gs
  529.         dec     [tempocount]            ; decrease the tempo counter
  530.         jle     pollmodulef0
  531.         lea     si,[tracks]             ; while in the same pattern row
  532.         xor     ebx,ebx                 ; update the track effects.
  533. pollmodulel0:
  534.         call    updatechannel
  535.         add     si,size track
  536.         inc     bx
  537.         cmp     bx,[numtracks]
  538.         jb      pollmodulel0
  539.         pop     gs es
  540.         popad
  541.         ret
  542.  
  543. pollmodulef0:                           ; advance to the next pattern row.
  544.         mov     al,[tempo]              ; update the tempo counter
  545.         mov     [tempocount],al
  546.         xor     edx,edx
  547.         lgs     dx,[moduleptr]          ; get module and pattern address
  548.         les     di,[pattptr]
  549.         cmp     [pattrow],40h           ; need to advance to the next order?
  550.         jb      pollmodulef2
  551.         xor     eax,eax                 ; reset the pattern row
  552.         mov     [pattrow],al
  553.         mov     al,[orderpos]           ; if we are at the end of the order
  554.         cmp     al,[orderlen]           ; list, loop to the beginning
  555.         jb      pollmodulef1
  556.         xor     al,al
  557.         mov     [orderpos],al
  558. pollmodulef1:
  559.         inc     [orderpos]              ; get the new pattern address
  560.         movzx   eax,[gs:edx+eax+module.orders]
  561.         les     di,[gs:edx+4*eax+module.patterns]
  562. pollmodulef2:
  563.         inc     [pattrow]               ; increase pattern row number
  564.         lea     si,[tracks]
  565.         xor     ebx,ebx                 ; read and interpret the next
  566. pollmodulel1:                           ; pattern row of events
  567.         call    readchannel
  568.         add     si,size track
  569.         add     di,4
  570.         inc     bx
  571.         cmp     bx,[numtracks]
  572.         jb      pollmodulel1
  573.         mov     [word low pattptr],di   ; save pattern row address
  574.         mov     [word high pattptr],es
  575.         pop     gs es
  576.         popad
  577.         ret
  578.  
  579. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  580. ; readchannel - read the next note event from the pattern sheet
  581. ; In:
  582. ;  EBX    = voice number
  583. ;  DS:SI  = track address
  584. ;  ES:DI  = pattern address
  585. ;  GS:EDX = module address
  586. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  587. readchannel:
  588.         pushad
  589.  
  590. ; check for new sample number . . .
  591.  
  592.         mov     al,[es:di+1]
  593.         test    al,al
  594.         je      readchannelf0
  595.         mov     [si+track.inst],al
  596.         movzx   eax,al
  597.         mov     al,[gs:edx+eax+module.sampvolume]
  598.         mov     [si+track.volume],al
  599.         mul     [musicvolume]
  600.         mov     [byte 4*ebx+voicevolume],ah
  601.  
  602. ; check for new note pitch . . .
  603.  
  604. readchannelf0:
  605.         mov     al,[es:di]
  606.         test    al,al
  607.         je      readchannelf1
  608.         movzx   eax,al
  609.         mov     [si+track.note],ax
  610.         cmp     [byte es:di+3],03h
  611.         je      readchannelf1
  612.         mov     ax,[2*eax+periodtable]
  613.         mov     [si+track.period],ax
  614.         mov     eax,[4*eax+pitchtable]
  615.         mov     [4*ebx+voicepitch],eax
  616.         movzx   eax,[si+track.inst]
  617.         mov     ecx,[gs:edx+4*eax+module.sampptr]
  618.         mov     [4*ebx+voicepos],ecx
  619.         mov     ecx,[gs:edx+4*eax+module.sampend]
  620.         mov     [word low 4*ebx+voiceend],cx
  621.         mov     ecx,[gs:edx+4*eax+module.samploop]
  622.         mov     [word low 4*ebx+voiceloop],cx
  623.  
  624. ; check the new track effect . . .
  625.  
  626. readchannelf1:
  627.         mov     dx,[es:di+2]
  628.         mov     [si+track.effect],dx
  629.         movzx   eax,dh
  630.         and     al,0Fh
  631.         call    [2*eax+efxtable]
  632.  
  633.         popad
  634.         ret
  635.  
  636. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  637. ; updatechannel - update the track using the current effect
  638. ; In:
  639. ;  EBX   = voice number
  640. ;  DS:SI = track address
  641. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  642. updatechannel:
  643.         pushad
  644.         mov     dx,[si+track.effect]
  645.         movzx   eax,dh
  646.         and     al,0Fh
  647.         call    [2*eax+efxtable2]
  648.         popad
  649.         ret
  650.  
  651. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  652. ; Protracker effects stuff
  653. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  654.  
  655. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  656. ; Effect jump tables
  657. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  658.  
  659.         align   2
  660.  
  661. label efxtable word
  662.         dw      efxarpeggio             ; 0 - arpeggio
  663.         dw      efxnull                 ; 1 - porta up
  664.         dw      efxnull                 ; 2 - porta down
  665.         dw      efxtoneporta            ; 3 - tone porta
  666.         dw      efxvibrato              ; 4 - vibrato
  667.         dw      efxnull                 ; 5 - tone+slide
  668.         dw      efxnull                 ; 6 - vibrato+slide
  669.         dw      efxtremolo              ; 7 - tremolo
  670.         dw      efxnull                 ; 8 - unused
  671.         dw      efxsampoffset           ; 9 - sample offset
  672.         dw      efxnull                 ; A - volume slide
  673.         dw      efxpattjump             ; B - pattern jump
  674.         dw      efxsetvolume            ; C - set volume
  675.         dw      efxbreak                ; D - break pattern
  676.         dw      efxnull                 ; E - extra effects
  677.         dw      efxsetspeed             ; F - set speed
  678.  
  679. label efxtable2 word
  680.         dw      efxarpeggio2            ; 0 - arpeggio
  681.         dw      efxportaup              ; 1 - porta up
  682.         dw      efxportadown            ; 2 - porta down
  683.         dw      efxtoneporta2           ; 3 - tone porta
  684.         dw      efxvibrato2             ; 4 - vibrato
  685.         dw      efxtoneslide            ; 5 - tone+slide
  686.         dw      efxvibslide             ; 6 - vibrato+slide
  687.         dw      efxtremolo2             ; 7 - tremolo
  688.         dw      efxnull                 ; 8 - unused
  689.         dw      efxnull                 ; 9 - sample offset
  690.         dw      efxvolslide             ; A - volume slide
  691.         dw      efxnull                 ; B - pattern jump
  692.         dw      efxnull                 ; C - set volume
  693.         dw      efxnull                 ; D - break pattern
  694.         dw      efxnull                 ; E - extra effects
  695.         dw      efxnull                 ; F - set speed
  696.  
  697. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  698. ; efxnull - dummy effect
  699. ; In:
  700. ;  EBX   = voice number
  701. ;  DS:SI = track address
  702. ;  DL    = effect parameter
  703. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  704. efxnull:
  705.         ret
  706.  
  707. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  708. ; efxarpeggio - arpeggio
  709. ; In:
  710. ;  EBX   = voice number
  711. ;  DS:SI = track address
  712. ;  DL    = effect parameter
  713. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  714. efxarpeggio:
  715.         test    dl,dl
  716.         je      efxnull
  717.         mov     dh,dl
  718.         and     dl,0Fh
  719.         shr     dh,4
  720.         movzx   eax,[si+track.note]
  721.         mov     cx,[2*eax+periodtable]
  722.         mov     [si+track.arptable],cx
  723.         add     al,dh
  724.         mov     cx,[2*eax+periodtable]
  725.         mov     [si+2+track.arptable],cx
  726.         sub     al,dh
  727.         add     al,dl
  728.         mov     cx,[2*eax+periodtable]
  729.         mov     [si+4+track.arptable],cx
  730.         ret
  731. efxarpeggio2:
  732.         test    dl,dl
  733.         je      efxnull
  734.         movzx   eax,[si+track.arptable]
  735.         xchg    [si+4+track.arptable],ax
  736.         xchg    [si+2+track.arptable],ax
  737.         mov     [si+track.arptable],ax
  738.         mov     eax,[4*eax+pitchtable]
  739.         mov     [4*ebx+voicepitch],eax
  740.         ret
  741.  
  742. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  743. ; efxportaup - slides the pitch up
  744. ; In:
  745. ;  EBX   = voice number
  746. ;  DS:SI = track address
  747. ;  DL    = effect parameter
  748. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  749. efxportaup:
  750.         xor     dh,dh
  751.         movzx   eax,[si+track.period]
  752.         sub     ax,dx
  753.         cmp     ax,28
  754.         jge     efxportaupf0
  755.         mov     ax,28
  756. efxportaupf0:
  757.         mov     [si+track.period],ax
  758.         mov     eax,[4*eax+pitchtable]
  759.         mov     [4*ebx+voicepitch],eax
  760.         ret
  761.  
  762. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  763. ; efxportadown - slides the pitch down
  764. ; In:
  765. ;  EBX   = voice number
  766. ;  DS:SI = track address
  767. ;  DL    = effect parameter
  768. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  769. efxportadown:
  770.         xor     dh,dh
  771.         movzx   eax,[si+track.period]
  772.         add     ax,dx
  773.         cmp     ax,3424
  774.         jle     efxportadownf0
  775.         mov     ax,3424
  776. efxportadownf0:
  777.         mov     [si+track.period],ax
  778.         mov     eax,[4*eax+pitchtable]
  779.         mov     [4*ebx+voicepitch],eax
  780.         ret
  781.  
  782. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  783. ; efxtoneporta - tone portamento
  784. ; In:
  785. ;  EBX   = voice number
  786. ;  DS:SI = track address
  787. ;  DL    = effect parameter
  788. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  789. efxtoneporta:
  790.         test    dl,dl
  791.         jne     efxtoneportaf0
  792.         mov     dl,[si+track.tonespeed]
  793. efxtoneportaf0:
  794.         mov     [si+track.tonespeed],dl
  795.         mov     [si+track.effect],dx
  796.         movzx   eax,[si+track.note]
  797.         mov     ax,[2*eax+periodtable]
  798.         mov     [si+track.destperiod],ax
  799.         ret
  800. efxtoneporta2:
  801.         xor     dh,dh
  802.         movzx   eax,[si+track.period]
  803.         mov     cx,[si+track.destperiod]
  804.         cmp     ax,cx
  805.         je      efxnull
  806.         jg      efxtoneportaf1
  807.         add     ax,dx
  808.         cmp     ax,cx
  809.         jle     efxtoneportaf2
  810.         mov     ax,cx
  811. efxtoneportaf2:
  812.         mov     [si+track.period],ax
  813.         mov     eax,[4*eax+pitchtable]
  814.         mov     [4*ebx+voicepitch],eax
  815.         ret
  816. efxtoneportaf1:
  817.         sub     ax,dx
  818.         cmp     ax,cx
  819.         jge     efxtoneportaf3
  820.         mov     ax,cx
  821. efxtoneportaf3:
  822.         mov     [si+track.period],ax
  823.         mov     eax,[4*eax+pitchtable]
  824.         mov     [4*ebx+voicepitch],eax
  825.         ret
  826.  
  827. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  828. ; efxvibrato - pitch vibrato
  829. ; In:
  830. ;  EBX   = voice number
  831. ;  DS:SI = track address
  832. ;  DL    = effect parameter
  833. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  834. efxvibrato:
  835.         mov     al,[si+track.vibparm]
  836.         mov     ah,al
  837.         and     ax,0F00Fh
  838.         test    dl,0Fh
  839.         jne     efxvibratof0
  840.         or      dl,al
  841. efxvibratof0:
  842.         test    dl,0F0h
  843.         jne     efxvibratof1
  844.         or      dl,ah
  845. efxvibratof1:
  846.         mov     [si+track.vibparm],dl
  847.         mov     [si+track.effect],dx
  848.         ret
  849. efxvibrato2:
  850.         mov     dh,dl
  851.         and     dx,0F00Fh
  852.         shr     dh,2
  853.         mov     al,[si+track.vibpos]
  854.         add     [si+track.vibpos],dh
  855.         mov     dh,al
  856.         shr     al,2
  857.         and     eax,1Fh
  858.         mov     al,[eax+sintable]
  859.         mul     dl
  860.         shr     ax,7
  861.         test    dh,dh
  862.         jge     efxvibratof2
  863.         neg     ax
  864. efxvibratof2:
  865.         add     ax,[si+track.period]
  866.         cmp     ax,28
  867.         jge     efxvibratof3
  868.         mov     ax,28
  869. efxvibratof3:
  870.         cmp     ax,3424
  871.         jle     efxvibratof4
  872.         mov     ax,3424
  873. efxvibratof4:
  874.         movzx   eax,ax
  875.         mov     eax,[4*eax+pitchtable]
  876.         mov     [4*ebx+voicepitch],eax
  877.         ret
  878.  
  879. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  880. ; efxtoneslide - volume slide and continue last portamento
  881. ; In:
  882. ;  EBX   = voice number
  883. ;  DS:SI = track address
  884. ;  DL    = effect parameter
  885. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  886. efxtoneslide:
  887.         call    efxvolslide
  888.         mov     dl,[si+track.tonespeed]
  889.         jmp     efxtoneporta
  890.  
  891. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  892. ; efxvibslide - volume slide and continue last pitch vibrato
  893. ; In:
  894. ;  EBX   = voice number
  895. ;  DS:SI = track address
  896. ;  DL    = effect parameter
  897. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  898. efxvibslide:
  899.         call    efxvolslide
  900.         mov     dl,[si+track.vibparm]
  901.         jmp     efxvibrato2
  902.  
  903. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  904. ; efxtremolo - volume vibrato
  905. ; In:
  906. ;  EBX   = voice number
  907. ;  DS:SI = track address
  908. ;  DL    = effect parameter
  909. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  910. efxtremolo:
  911.         mov     al,[si+track.tremparm]
  912.         mov     ah,al
  913.         and     ax,0F00Fh
  914.         test    dl,0Fh
  915.         jne     efxtremolof0
  916.         or      dl,al
  917. efxtremolof0:
  918.         test    dl,0F0h
  919.         jne     efxtremolof1
  920.         or      dl,ah
  921. efxtremolof1:
  922.         mov     [si+track.tremparm],dl
  923.         mov     [si+track.effect],dx
  924.         ret
  925. efxtremolo2:
  926.         mov     dh,dl
  927.         and     dx,0F00Fh
  928.         shr     dh,2
  929.         mov     al,[si+track.trempos]
  930.         add     [si+track.trempos],dh
  931.         mov     dh,al
  932.         shr     al,2
  933.         and     eax,1Fh
  934.         mov     al,[eax+sintable]
  935.         mul     dl
  936.         shr     ax,6
  937.         test    dh,dh
  938.         jge     efxtremolof2
  939.         neg     ax
  940. efxtremolof2:
  941.         add     al,[si+track.volume]
  942.         jge     efxtremolof3
  943.         xor     al,al
  944. efxtremolof3:
  945.         cmp     al,40h
  946.         jle     efxtremolof4
  947.         mov     al,40h
  948. efxtremolof4:
  949.         mul     [musicvolume]
  950.         mov     [byte 4*ebx+voicevolume],ah
  951.         ret
  952.  
  953. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  954. ; efxsampoffset - set the sample offset
  955. ; In:
  956. ;  EBX   = voice number
  957. ;  DS:SI = track address
  958. ;  DL    = effect parameter
  959. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  960. efxsampoffset:
  961.         movzx   eax,[si+track.inst]
  962.         xor     esi,esi
  963.         lgs     si,[moduleptr]
  964.         mov     eax,[gs:esi+4*eax+module.sampptr]
  965.         mov     dh,dl
  966.         xor     dl,dl
  967.         add     ax,dx
  968.         mov     [word low 4*ebx+voicepos],ax
  969.         ret
  970.  
  971. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  972. ; efxvolslide - volume slide
  973. ; In:
  974. ;  EBX   = voice number
  975. ;  DS:SI = track address
  976. ;  DL    = effect parameter
  977. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  978. efxvolslide:
  979.         mov     al,[si+track.volume]
  980.         mov     dh,dl
  981.         shr     dl,4
  982.         je      efxvolslidef0
  983.         add     al,dl
  984.         cmp     al,40h
  985.         jle     efxvolslidef1
  986.         mov     al,40h
  987. efxvolslidef1:
  988.         mov     [si+track.volume],al
  989.         mul     [musicvolume]
  990.         mov     [byte 4*ebx+voicevolume],ah
  991.         ret
  992. efxvolslidef0:
  993.         sub     al,dh
  994.         jge     efxvolslidef2
  995.         xor     al,al
  996. efxvolslidef2:
  997.         mov     [si+track.volume],al
  998.         mul     [musicvolume]
  999.         mov     [byte 4*ebx+voicevolume],ah
  1000.         ret
  1001.  
  1002. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1003. ; efxpattjump - jump to order pattern
  1004. ; In:
  1005. ;  EBX   = voice number
  1006. ;  DS:SI = track address
  1007. ;  DL    = effect parameter
  1008. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1009. efxpattjump:
  1010.         mov     [orderpos],dl
  1011.         mov     [pattrow],40h
  1012.         ret
  1013.  
  1014. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1015. ; efxsetvolume - set volume
  1016. ; In:
  1017. ;  EBX   = voice number
  1018. ;  DS:SI = track address
  1019. ;  DL    = effect parameter
  1020. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1021. efxsetvolume:
  1022.         mov     al,dl
  1023.         mov     [si+track.volume],al
  1024.         mul     [musicvolume]
  1025.         mov     [byte 4*ebx+voicevolume],ah
  1026.         ret
  1027.  
  1028. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1029. ; efxbreak - break pattern
  1030. ; In:
  1031. ;  EBX   = voice number
  1032. ;  DS:SI = track address
  1033. ;  DL    = effect parameter
  1034. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1035. efxbreak:
  1036.         mov     [pattrow],40h
  1037.         ret
  1038.  
  1039. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1040. ; efxsetspeed - set the tempo or BPM speed
  1041. ; In:
  1042. ;  EBX   = voice number
  1043. ;  DS:SI = track address
  1044. ;  DL    = effect parameter
  1045. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1046. efxsetspeed:
  1047.         test    dl,dl
  1048.         je      efxnull
  1049.         cmp     dl,20h
  1050.         jae     efxsetbpm
  1051.         mov     [tempo],dl
  1052.         mov     [tempocount],dl
  1053.         ret
  1054. efxsetbpm:
  1055.         mov     [bpm],dl
  1056.         call    mixstarttimer
  1057.         ret
  1058.  
  1059. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  1060. ; Sound Blaster Driver highlevel stuff
  1061. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  1062.  
  1063. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1064. ; mixinit - initialize the sound driver
  1065. ; In:
  1066. ;  AX = mixing speed in hertz
  1067. ;  BL = number of voices
  1068. ;  DX = I/O port address
  1069. ;  CL = IRQ level
  1070. ;  CH = DRQ channel
  1071. ;  BH = polling mode
  1072. ; Out:
  1073. ;  CF = status
  1074. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1075. mixinit:
  1076.         pushad
  1077.         push    es
  1078.  
  1079.         cmp     [playing],0
  1080.         stc
  1081.         jne     mixinitd0
  1082.  
  1083. ; setup sound card parameters
  1084.  
  1085.         mov     [manualmode],bh
  1086.         xor     bh,bh
  1087.         mov     [mixfreq],ax
  1088.         mov     [numvoices],bx
  1089.         mov     [ioaddr],dx
  1090.         mov     [irqnum],cl
  1091.         mov     [drqnum],ch
  1092.  
  1093. ; check if the sound card is present
  1094.  
  1095.         call    sbreset
  1096.         jc      mixinitd0
  1097.  
  1098. ; setup timer and double buffer variables
  1099.  
  1100.         mov     [timerproc],offset nulltimer
  1101.         xor     ax,ax
  1102.         mov     [bufoff],ax
  1103.         mov     [timeracc],ax
  1104.         mov     [timerspeed],256
  1105.  
  1106. ; clear voice parameters
  1107.  
  1108.         push    es
  1109.         mov     ax,ds
  1110.         mov     es,ax
  1111.         cld
  1112.         lea     di,[voicepos]
  1113.         mov     cx,6*MAXVOICES
  1114.         xor     eax,eax
  1115.         rep     stosd
  1116.         pop     es
  1117.  
  1118. ; allocate conventional memory for the DMA buffer, the volume table,
  1119. ; the mixing buffer and the boosting table.
  1120.  
  1121. ; NOTE: there are problems allocating memory using INT 21h AH=48h under
  1122. ;       Borland C++ 3.1 so I am using an static data segment.
  1123.  
  1124.         mov     ax,fardataseg
  1125.         mov     [bufsel],ax
  1126.         movzx   eax,ax
  1127.         shl     eax,4
  1128.  
  1129. ; set the address of the mixing buffer and boosting table
  1130.  
  1131.         mov     [mixbuffer],0
  1132.         mov     [boosttable],DMABUFLEN
  1133.         add     eax,DMABUFLEN+2048
  1134.  
  1135. ; get the address of the DMA buffer and volume table
  1136.  
  1137.         mov     ecx,DMABUFLEN
  1138.         lea     edx,[eax+ecx]
  1139.  
  1140. ; check for cross-pages in the DMA buffer and align the Volume table
  1141.  
  1142.         mov     esi,eax
  1143.         add     si,cx
  1144.         jnc     mixinitf0
  1145.         mov     edx,eax
  1146.         add     eax,VOLBUFLEN
  1147. mixinitf0:
  1148.         movzx   esi,[bufsel]
  1149.         shl     esi,4
  1150.         sub     eax,esi
  1151.         sub     edx,esi
  1152.         add     dx,255
  1153.         xor     dl,dl
  1154.         mov     [bufptr],ax
  1155.         mov     [voltable],dx
  1156.  
  1157. ; clear DMA buffer with centered samples
  1158.  
  1159.         push    es
  1160.         cld
  1161.         mov     es,[bufsel]
  1162.         mov     di,[bufptr]
  1163.         mov     cx,DMABUFLEN
  1164.         mov     al,80h
  1165.         rep     stosb
  1166.         pop     es
  1167.  
  1168. ; build volume table and boosting table
  1169.  
  1170.         push    es
  1171.         mov     cl,6
  1172.         mov     es,[bufsel]
  1173.         mov     di,[voltable]
  1174.         xor     bx,bx
  1175. mixinitl0:
  1176.         mov     al,bl
  1177.         imul    bh
  1178.         sar     ax,cl
  1179.         mov     [es:di],al
  1180.         inc     di
  1181.         inc     bl
  1182.         jne     mixinitl0
  1183.         inc     bh
  1184.         cmp     bh,40h
  1185.         jbe     mixinitl0
  1186.         pop     es
  1187.  
  1188.         push    es
  1189.         cld
  1190.         mov     es,[bufsel]
  1191.         mov     di,[boosttable]
  1192.         mov     cx,768
  1193.         xor     ax,ax
  1194.         rep     stosb
  1195.         mov     cx,512
  1196. mixinitl1:
  1197.         mov     [es:di],ah
  1198.         add     ax,80h
  1199.         inc     di
  1200.         loop    mixinitl1
  1201.         mov     cx,768
  1202.         dec     al
  1203.         rep     stosb
  1204.         pop     es
  1205.  
  1206. ; initialize the sound card for output
  1207.  
  1208.         call    dmasetup
  1209.         call    irqsetup
  1210.         call    sbsetup
  1211.  
  1212. ; dont use the timer interrupt for manual polling mode
  1213.  
  1214.         cmp     [manualmode],0
  1215.         jne     mixinitf1
  1216.  
  1217. ; install timer interrupt to poll the driver
  1218.  
  1219.         push    es
  1220.         mov     ax,cs
  1221.         mov     es,ax
  1222.         lea     bx,[mixtimer]
  1223.         mov     cl,0
  1224.         call    irqsetvect
  1225.         mov     [oldtimeroff],bx
  1226.         mov     [oldtimersel],es
  1227.         pop     es
  1228.  
  1229. ; set the timer frequency to 70 hertz
  1230.  
  1231.         cli
  1232.         mov     al,36h
  1233.         out     43h,al
  1234.         mov     ax,TIMERRATE
  1235.         out     40h,al
  1236.         mov     al,ah
  1237.         out     40h,al
  1238.         sti
  1239.  
  1240. ; set driver playing status
  1241.  
  1242. mixinitf1:
  1243.         mov     [playing],1
  1244.         clc
  1245.  
  1246. mixinitd0:
  1247.         pop     es
  1248.         popad
  1249.         ret
  1250.  
  1251. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1252. ; mixdone - deinitialize the sound driver
  1253. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1254. mixdone:
  1255.         pushad
  1256.         push    es
  1257.  
  1258.         cmp     [playing],1
  1259.         jne     mixdoned0
  1260.  
  1261. ; the timer interrupt was modified if we are using the timer polling mode
  1262.  
  1263.         cmp     [manualmode],0
  1264.         jne     mixdonef0
  1265.  
  1266. ; restore the timer frequency to 18.2 hertz
  1267.  
  1268.         cli
  1269.         mov     al,36h
  1270.         out     43h,al
  1271.         xor     al,al
  1272.         out     40h,al
  1273.         out     40h,al
  1274.         sti
  1275.  
  1276. ; deinstall timer interrupt used to poll the driver
  1277.  
  1278.         push    es
  1279.         mov     bx,[oldtimeroff]
  1280.         mov     es,[oldtimersel]
  1281.         mov     cl,0
  1282.         call    irqsetvect
  1283.         pop     es
  1284.  
  1285. ; deinitialize the sound card output
  1286.  
  1287. mixdonef0:
  1288.         call    sbdone
  1289.         call    irqdone
  1290.         call    dmadone
  1291.  
  1292. ; set driver stopped status
  1293.  
  1294.         mov     [playing],0
  1295.  
  1296. mixdoned0:
  1297.         pop     es
  1298.         popad
  1299.         ret
  1300.  
  1301. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1302. ; mixtimer - timer interrupt routine used to poll the sound driver
  1303. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1304. mixtimer:
  1305.         push    ax
  1306.         push    ds
  1307.         mov     ax,@data
  1308.         mov     ds,ax
  1309.         call    mixpoll                 ; poll the sound system
  1310.         add     [oldtimeracc],TIMERRATE
  1311.         jnc     mixtimerf0              ; time to call the old IRQ0 vector?
  1312.         pushf                           ; yes, jump to the old IRQ0 service
  1313.         call    [dword oldtimeroff]
  1314.         jmp     mixtimerd0
  1315. mixtimerf0:
  1316.         mov     al,20h                  ; nope, send PIC acknowledge and exit
  1317.         out     20h,al
  1318. mixtimerd0:
  1319.         pop     ds
  1320.         pop     ax
  1321.         iret
  1322.  
  1323. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1324. ; mixdetect - detect the sound card configuration
  1325. ; Out:
  1326. ;  DX = I/O Port
  1327. ;  CL = IRQ level
  1328. ;  CH = DMA channel
  1329. ;  CF = status
  1330. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1331. mixdetect:
  1332.         cmp     [playing],1             ; do not try to autodetect
  1333.         stc                             ; if we are already playing
  1334.         je      mixdetectd0
  1335.         call    sbdetect
  1336. mixdetectd0:
  1337.         ret
  1338.  
  1339. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1340. ; mixsettimerproc - set the timer procedure
  1341. ; In:
  1342. ;  CS:DX = timer routine address
  1343. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1344. mixsettimerproc:
  1345.         mov     [timerproc],dx          ; set the timer callback address
  1346.         ret
  1347.  
  1348. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1349. ; mixstarttimer - start the timer at the specified speed
  1350. ; In:
  1351. ;  DL = timer speed in beats per minute (BPMs)
  1352. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1353. mixstarttimer:
  1354.         push    ax
  1355.         push    bx
  1356.         push    dx
  1357.         mov     bh,dl                   ; set the timer callback speed
  1358.         xor     bl,bl                   ; to 24/60*BPM hertz
  1359.         mov     ax,[mixfreq]
  1360.         mov     dx,0280h
  1361.         mul     dx
  1362.         div     bx
  1363.         mov     [timerspeed],ax
  1364.         pop     dx
  1365.         pop     bx
  1366.         pop     ax
  1367.         ret
  1368.  
  1369. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1370. ; mixstoptimer - stop the timer routine
  1371. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1372. mixstoptimer:
  1373.         mov     [timerproc],offset nulltimer
  1374. nulltimer:
  1375.         ret
  1376.  
  1377. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1378. ; mixvoice - mixes the voice samples
  1379. ; In:
  1380. ;  EBX   = voice number (*4)
  1381. ;  CX    = number of samples
  1382. ;  ES:DI = buffer address
  1383. ; Out:
  1384. ;  ES:DI = buffer end address
  1385. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1386. mixvoice:
  1387.  
  1388.         macro   mixcode OPCODE
  1389.         local   mixcodel0,mixjmptable
  1390.  
  1391.         push    eax
  1392.         push    bx
  1393.         push    cx
  1394.         push    dx
  1395.         push    bp
  1396.         push    si
  1397.  
  1398.         push    ds
  1399.         push    es
  1400.         push    bx
  1401.         mov     ax,[voltable]
  1402.         mov     dl,[byte bx+3+voicefrac]
  1403.         mov     dh,[byte bx+1+voicepitch]
  1404.         mov     bp,[word bx+2+voicepitch]
  1405.         add     ah,[byte bx+voicevolume]
  1406.         les     si,[bx+voicepos]
  1407.         mov     ds,[bufsel]
  1408.         mov     bx,ax
  1409.  
  1410.         movzx   eax,cl
  1411.         and     al,31
  1412.         shr     cx,5
  1413.         movzx   edi,di
  1414.         lea     edi,[edi+2*eax-2*32]
  1415.         jmp     [2*eax+mixjmptable]
  1416.  
  1417.         align   2
  1418. mixcodel0:
  1419.         I=0
  1420.         rept    32
  1421. CODESTART=$
  1422.         mov     bl,[es:si]
  1423.         add     dl,dh
  1424.         movsx   ax,[byte ds:bx]
  1425.         adc     si,bp
  1426.         OPCODE  [ds:di+I],ax
  1427. CODELEN=$-CODESTART
  1428.         I=I+2
  1429.         endm
  1430.         add     di,2*32
  1431.         dec     cx
  1432.         jge     mixcodel0
  1433.  
  1434.         pop     bx
  1435.         pop     es
  1436.         pop     ds
  1437.         mov     [word low bx+voicepos],si
  1438.         mov     [byte bx+3+voicefrac],dl
  1439.  
  1440.         pop     si
  1441.         pop     bp
  1442.         pop     dx
  1443.         pop     cx
  1444.         pop     bx
  1445.         pop     eax
  1446.         ret
  1447.  
  1448.         align   2
  1449.         label mixjmptable word
  1450.         I=CODESTART+CODELEN
  1451.         rept    32
  1452.         dw      I
  1453.         I=I-CODELEN
  1454.         endm
  1455.         endm
  1456.  
  1457.         test    bx,bx
  1458.         je      mixvoicef0
  1459.         mixcode add
  1460. mixvoicef0:
  1461.         mixcode mov
  1462.  
  1463. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1464. ; mixvoices - mixes all the voices
  1465. ; In:
  1466. ;  ES:DI = buffer address
  1467. ;  CX    = number of samples
  1468. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1469. mixvoices:
  1470.         pushad
  1471.  
  1472.         xor     ebx,ebx
  1473. mixvoicesl0:
  1474.         push    bx
  1475.         push    cx
  1476.         push    di
  1477.         shl     bx,2
  1478.         mov     bp,cx
  1479.  
  1480. mixvoicesl1:
  1481.         mov     cx,bp
  1482.         mov     dx,[word low bx+voicepos]
  1483.         mov     ax,[word low bx+voiceend]
  1484.         cmp     dx,ax
  1485.         jb      mixvoicesf0
  1486.         sub     dx,ax
  1487.         add     dx,[word low bx+voiceloop]
  1488.         cmp     dx,ax
  1489.         jae     mixvoicesc0
  1490.         mov     [word low bx+voicepos],dx
  1491.  
  1492. mixvoicesf0:
  1493.         sub     ax,dx
  1494.         shl     eax,16
  1495.         mov     edx,[bx+voicefrac]
  1496.         shr     edx,16
  1497.         sub     eax,edx
  1498.  
  1499.         movzx   edx,cx
  1500.         mov     esi,[bx+voicepitch]
  1501.         imul    edx,esi
  1502.         cmp     edx,eax
  1503.         jbe     mixvoicesf1
  1504.         dec     eax
  1505.         xor     edx,edx
  1506.         add     eax,esi
  1507.         adc     edx,edx
  1508.         div     esi
  1509.         mov     cx,ax
  1510.  
  1511. mixvoicesf1:
  1512.         call    mixvoice
  1513.         sub     bp,cx
  1514.         jg      mixvoicesl1
  1515.  
  1516.         pop     di
  1517.         pop     cx
  1518.         pop     bx
  1519.         inc     bx
  1520.         cmp     bx,[numvoices]
  1521.         jb      mixvoicesl0
  1522.  
  1523.         popad
  1524.         ret
  1525.  
  1526. mixvoicesc0:
  1527.         test    bx,bx
  1528.         jne     mixvoicesc1
  1529.         cld
  1530.         xor     ax,ax
  1531.         rep     stosw
  1532.  
  1533. mixvoicesc1:
  1534.         pop     di
  1535.         pop     cx
  1536.         pop     bx
  1537.         inc     bx
  1538.         cmp     bx,[numvoices]
  1539.         jb      mixvoicesl0
  1540.  
  1541.         popad
  1542.         ret
  1543.  
  1544. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1545. ; mixpoll - updates the output buffer
  1546. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1547. mixpoll:
  1548.         pushad
  1549.         push    es
  1550.  
  1551. ; get the 16 bit mixing buffer address
  1552.  
  1553.         mov     cx,DMABUFLEN/2
  1554.         mov     es,[bufsel]
  1555.         mov     di,[mixbuffer]
  1556.  
  1557. ; check if we can fill the current half buffer with samples
  1558.  
  1559.         call    dmagetpos
  1560.         cmp     ax,cx
  1561.         jae     mixpollf3
  1562.         cmp     [bufoff],cx
  1563.         je      mixpollf4
  1564.         jmp     mixpolld0
  1565. mixpollf3:
  1566.         cmp     [bufoff],cx
  1567.         je      mixpolld0
  1568.  
  1569. ; fill the mixing buffer and polls the timer callback routine
  1570.  
  1571. mixpollf4:
  1572.         mov     ax,[timeracc]
  1573.         mov     bp,cx
  1574. mixpolll0:
  1575.         test    ax,ax
  1576.         jg      mixpollf0
  1577.         call    [timerproc]
  1578.         add     ax,[timerspeed]
  1579. mixpollf0:
  1580.         mov     cx,ax
  1581.         add     cx,63
  1582.         and     cl,not 63
  1583.         cmp     cx,bp
  1584.         jle     mixpollf1
  1585.         mov     cx,bp
  1586. mixpollf1:
  1587.         call    mixvoices
  1588.         add     di,cx
  1589.         add     di,cx
  1590.         sub     ax,cx
  1591.         sub     bp,cx
  1592.         jg      mixpolll0
  1593.         mov     [timeracc],ax
  1594.  
  1595. ; translate 16-bit signed samples to 8-bit unsigned samples
  1596.  
  1597.         push    ds
  1598.         mov     cx,DMABUFLEN/2
  1599.         mov     si,[mixbuffer]
  1600.         movzx   eax,[bufptr]
  1601.         add     ax,[bufoff]
  1602.         xor     [bufoff],cx
  1603.         mov     di,[boosttable]
  1604.         add     di,1024
  1605.         shr     cx,4
  1606.         mov     ds,[bufsel]
  1607. mixpolll2:
  1608.         I=0
  1609.         rept    4
  1610.         mov     bx,[si+8*I+4]
  1611.         mov     dl,[di+bx]
  1612.         mov     bx,[si+8*I+6]
  1613.         mov     dh,[di+bx]
  1614.         shl     edx,16
  1615.         mov     bx,[si+8*I]
  1616.         mov     dl,[di+bx]
  1617.         mov     bx,[si+8*I+2]
  1618.         mov     dh,[di+bx]
  1619.         mov     [eax+4*I],edx
  1620.         I=I+1
  1621.         endm
  1622.         add     si,2*16
  1623.         add     ax,16
  1624.         dec     cx
  1625.         jg      mixpolll2
  1626.         pop     ds
  1627.  
  1628. mixpolld0:
  1629.         pop     es
  1630.         popad
  1631.         ret
  1632.  
  1633. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  1634. ; Sound Blaster DSP lowlevel stuff
  1635. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  1636.  
  1637. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1638. ; sbwrite - send a command/data byte to the DSP chip
  1639. ; In:
  1640. ;  AL = command/data byte
  1641. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1642. sbwrite:
  1643.         push    ax
  1644.         push    cx
  1645.         push    dx
  1646.         mov     dx,[ioaddr]
  1647.         add     dx,0Ch
  1648.         mov     ah,al
  1649.         xor     cx,cx                   ; wait until the write buffer
  1650. sbwritel0:                              ; status port (2XCh) bit 7 is clear
  1651.         in      al,dx
  1652.         and     al,80h
  1653.         loopnz  sbwritel0
  1654.         mov     al,ah                   ; write value in the write
  1655.         out     dx,al                   ; data port (2XCh)
  1656.         pop     dx
  1657.         pop     cx
  1658.         pop     ax
  1659.         ret
  1660.  
  1661. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1662. ; sbreset - reset the Sound Blaster DSP chip
  1663. ; Out:
  1664. ;  CF = status
  1665. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1666. sbreset:
  1667.         push    ax
  1668.         push    bx
  1669.         push    cx
  1670.         push    dx
  1671.         mov     bx,64                   ; try to reset upto 64 times
  1672. sbresetl1:
  1673.         mov     dx,[ioaddr]
  1674.         add     dx,06h
  1675.         mov     al,1                    ; write 1 to the reset port (2X6h)
  1676.         out     dx,al
  1677.         xor     ah,ah                   ; wait at least 3 microseconds
  1678. sbresetl2:
  1679.         in      al,dx
  1680.         dec     ah
  1681.         jne     sbresetl2
  1682.         xor     al,al                   ; write 0 to the reset port (2X6h)
  1683.         out     dx,al
  1684.         add     dx,08h
  1685.         mov     cx,0400h                ; wait until the data available
  1686. sbresetl0:                              ; status port (2XEh) bit 7 is set
  1687.         in      al,dx
  1688.         and     al,80h
  1689.         loopz   sbresetl0
  1690.         sub     dx,04h                  ; read the read data port (2XAh)
  1691.         in      al,dx
  1692.         cmp     al,0AAh
  1693.         clc
  1694.         je      sbresetd0               ; check the ready byte value
  1695.         dec     bx
  1696.         jne     sbresetl1
  1697.         stc
  1698. sbresetd0:
  1699.         pop     dx
  1700.         pop     cx
  1701.         pop     bx
  1702.         pop     ax
  1703.         ret
  1704.  
  1705. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1706. ; sbsetup - start the DMA output
  1707. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1708. sbsetup:
  1709.         push    ax
  1710.         push    dx
  1711.         mov     al,0D1h                 ; turn on the speaker
  1712.         call    sbwrite
  1713.         mov     al,40h                  ; set the playback rate
  1714.         call    sbwrite
  1715.         mov     ax,1000
  1716.         mul     ax
  1717.         div     [mixfreq]
  1718.         neg     ax
  1719.         call    sbwrite
  1720.         mov     al,14h                  ; start the lowspeed 8 bit DMA
  1721.         call    sbwrite                 ; mode transfer to the DAC
  1722.         mov     al,0FFh
  1723.         call    sbwrite
  1724.         call    sbwrite
  1725.         pop     dx
  1726.         pop     ax
  1727.         ret
  1728.  
  1729. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1730. ; sbdone - shut down the DMA output
  1731. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1732. sbdone:
  1733.         push    ax
  1734.         call    sbreset                 ; reset the DSP chip
  1735.         mov     al,0D3h
  1736.         call    sbwrite                 ; turn off the speaker
  1737.         pop     ax
  1738.         ret
  1739.  
  1740. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1741. ; sbdetect - Detect the Sound Blaster I/O Port, IRQ level and DMA channel
  1742. ; Out:
  1743. ;  DX = I/O port address
  1744. ;  CL = IRQ level
  1745. ;  CH = DMA channel
  1746. ;  CF = status
  1747. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1748. sbdetect:
  1749.         mov     dx,210h                 ; scan the ports 210h..260h
  1750. sbdetectl0:
  1751.         mov     [ioaddr],dx             ; check if there is a SB card
  1752.         call    sbreset                 ; trying to reset the DSP chip
  1753.         jnc     sbdetectf0
  1754.         add     dx,10h
  1755.         cmp     dx,260h
  1756.         jbe     sbdetectl0
  1757.         xor     dx,dx
  1758.         xor     cx,cx
  1759.         stc
  1760.         ret
  1761. sbdetectf0:
  1762.         push    ax
  1763.         push    bx
  1764.         push    cx
  1765.         push    es
  1766.  
  1767.         irp     I,<2,3,5,7,10>          ; install IRQ traps
  1768.         push    cs
  1769.         pop     es
  1770.         lea     bx,[irqtest&I]
  1771.         mov     cx,I
  1772.         call    irqsetvect
  1773.         call    irqsetmask
  1774.         push    bx
  1775.         push    es
  1776.         endm
  1777.  
  1778.         mov     [irqnum],0
  1779.  
  1780.         mov     al,0F2h                 ; ask to the DSP to raise a IRQ
  1781.         call    sbwrite
  1782.  
  1783.         xor     cx,cx                   ; wait until some IRQ occurs
  1784. sbdetectl1:
  1785.         cmp     [irqnum],0
  1786.         loope   sbdetectl1
  1787.  
  1788.         irp     I,<10,7,5,3,2>          ; deinstall IRQ traps
  1789.         pop     es
  1790.         pop     bx
  1791.         mov     cx,0100h+I
  1792.         call    irqsetmask
  1793.         call    irqsetvect
  1794.         endm
  1795.  
  1796.         pop     es
  1797.         pop     cx
  1798.         pop     bx
  1799.         pop     ax
  1800.         mov     dx,[ioaddr]             ; return the SB parameters
  1801.         mov     cl,[irqnum]
  1802.         xor     ch,ch
  1803.         sub     ch,cl
  1804.         mov     ch,1
  1805.         cmc
  1806.         ret
  1807.  
  1808. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  1809. ; Sound Blaster DMA lowlevel stuff
  1810. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  1811.  
  1812. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1813. ; dmasetup - setup the DMA buffer parameters
  1814. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1815. dmasetup:
  1816.         push    eax
  1817.         push    bx
  1818.         push    cx
  1819.         push    dx
  1820.  
  1821.         mov     bl,[drqnum]
  1822.         mov     al,bl
  1823.         or      al,04h                  ; reset the DMA channel
  1824.         out     0Ah,al
  1825.         out     0Ch,al                  ; clear the flip flop
  1826.         mov     al,bl
  1827.         or      al,58h                  ; set the autoinit mode
  1828.         out     0Bh,al
  1829.         movzx   dx,bl
  1830.         add     dx,dx
  1831.         push    edx                     ; set the buffer address
  1832.         movzx   eax,[bufsel]
  1833.         movzx   edx,[bufptr]
  1834.         shl     eax,4
  1835.         add     eax,edx
  1836.         pop     edx
  1837.         out     dx,al
  1838.         mov     al,ah
  1839.         out     dx,al
  1840.         inc     dx
  1841.         mov     ax,DMABUFLEN            ; set the buffer length
  1842.         dec     ax
  1843.         out     dx,al
  1844.         mov     al,ah
  1845.         out     dx,al
  1846.         mov     edx,82818387h           ; set the buffer page
  1847.         mov     cl,bl
  1848.         shl     cl,3
  1849.         shr     edx,cl
  1850.         xor     dh,dh
  1851.         shr     eax,16
  1852.         out     dx,al
  1853.         mov     al,bl                   ; unlock the DMA channel
  1854.         out     0Ah,al
  1855.  
  1856.         pop     dx
  1857.         pop     cx
  1858.         pop     bx
  1859.         pop     eax
  1860.         ret
  1861.  
  1862. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1863. ; dmadone - shut down the DMA controller
  1864. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1865. dmadone:
  1866.         push    ax
  1867.         mov     al,[drqnum]             ; reset the DMA channel
  1868.         or      al,04h
  1869.         out     0Ah,al
  1870.         pop     ax
  1871.         ret
  1872.  
  1873. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1874. ; dmagetpos - return the DMA buffer relative position
  1875. ; Out:
  1876. ;  AX = buffer relative position
  1877. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1878. dmagetpos:
  1879.         push    cx
  1880.         push    dx
  1881.         out     0Ch,al                  ; clear the flip flop
  1882.         mov     dl,[drqnum]
  1883.         xor     dh,dh
  1884.         add     dl,dl
  1885.         inc     dl
  1886.         in      al,dx                   ; read the DMA counter
  1887.         mov     ah,al
  1888.         in      al,dx
  1889.         xchg    al,ah
  1890. dmagetposl0:
  1891.         mov     cx,ax                   ; read again the DMA counter
  1892.         in      al,dx
  1893.         mov     ah,al
  1894.         in      al,dx
  1895.         xchg    al,ah
  1896.         sub     cx,ax
  1897.         cmp     cx,+16                  ; both values are near?
  1898.         jg      dmagetposl0             ; nope, try again
  1899.         cmp     cx,-16
  1900.         jl      dmagetposl0
  1901.         neg     ax                      ; get the position relative
  1902.         add     ax,DMABUFLEN            ; to the start of the buffer
  1903.         pop     dx
  1904.         pop     cx
  1905.         ret
  1906.  
  1907. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  1908. ; Sound Blaster IRQ lowlevel stuff
  1909. ;░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒░▒
  1910.  
  1911. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1912. ; irqsetvect - set the IRQ handler routine
  1913. ; In:
  1914. ;  ES:BX = IRQ handler routine address
  1915. ;  CL = IRQ level
  1916. ; Out:
  1917. ;  ES:BX = previous IRQ handler address
  1918. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1919. irqsetvect:
  1920.         push    ax
  1921.         push    cx
  1922.         push    dx
  1923.  
  1924. ; get the PIC interrupt master and slave base address
  1925.  
  1926.         mov     dx,0870h
  1927.  
  1928. ; get the IDT interrupt slot number for the IRQ number
  1929.  
  1930.         mov     al,cl
  1931.         cmp     al,08h
  1932.         jb      irqsetvectf0
  1933.         mov     dh,dl
  1934.         sub     al,08h
  1935. irqsetvectf0:
  1936.         add     al,dh
  1937.  
  1938. ; saves and change the IRQ handler routine
  1939.  
  1940.         push    ds
  1941.         push    es
  1942.         push    bx
  1943.         mov     ah,35h
  1944.         int     21h
  1945.         pop     dx
  1946.         pop     ds
  1947.         push    es
  1948.         push    bx
  1949.         mov     ah,25h
  1950.         int     21h
  1951.         pop     bx
  1952.         pop     es
  1953.         pop     ds
  1954.  
  1955.         pop     dx
  1956.         pop     cx
  1957.         pop     ax
  1958.         ret
  1959.  
  1960. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1961. ; irqsetmask - enable or disable the IRQ in the interrupt mask registers
  1962. ; In:
  1963. ;  CL = IRQ level
  1964. ;  CH = enable (=0) or disable (=1)
  1965. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1966. irqsetmask:
  1967.         push    ax
  1968.         push    dx
  1969.  
  1970.         cli
  1971.         in      al,0A1h                 ; enable or disable the specified
  1972.         mov     ah,al                   ; IRQ using the PIC interrupt
  1973.         in      al,21h                  ; mask registers
  1974.         mov     dx,1
  1975.         shl     dx,cl
  1976.         not     dx
  1977.         and     ax,dx
  1978.         mov     dl,ch
  1979.         shl     dx,cl
  1980.         or      ax,dx
  1981.         out     21h,al
  1982.         mov     al,ah
  1983.         out     0A1h,al
  1984.         sti
  1985.  
  1986.         pop     dx
  1987.         pop     ax
  1988.         ret
  1989.  
  1990. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1991. ; irqsetup - install the IRQ handler routine
  1992. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1993. irqsetup:
  1994.         push    ax
  1995.         push    bx
  1996.         push    cx
  1997.  
  1998. ; set the IRQ handler routine and saves the previous vector
  1999.  
  2000.         push    es
  2001.         mov     ax,cs
  2002.         mov     es,ax
  2003.         lea     bx,[irqhandler]
  2004.         mov     cl,[irqnum]
  2005.         call    irqsetvect
  2006.         mov     [oldirqoff],bx
  2007.         mov     [oldirqsel],es
  2008.         pop     es
  2009.  
  2010. ; enable the IRQ signals in the PIC interrupt mask
  2011.  
  2012.         mov     cl,[irqnum]
  2013.         mov     ch,0
  2014.         call    irqsetmask
  2015.  
  2016.         pop     cx
  2017.         pop     bx
  2018.         pop     ax
  2019.         ret
  2020.  
  2021. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2022. ; irqdone - restores the old IRQ handler routine
  2023. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2024. irqdone:
  2025.         push    bx
  2026.         push    cx
  2027.  
  2028. ; disable IRQ signals in the PIC interrupt mask register
  2029.  
  2030.         mov     cl,[irqnum]
  2031.         mov     ch,1
  2032.         call    irqsetmask
  2033.  
  2034. ; restore the old IRQ handler routine
  2035.  
  2036.         push    es
  2037.         mov     bx,[oldirqoff]
  2038.         mov     es,[oldirqsel]
  2039.         mov     cl,[irqnum]
  2040.         call    irqsetvect
  2041.         pop     es
  2042.  
  2043.         pop     cx
  2044.         pop     bx
  2045.         ret
  2046.  
  2047. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2048. ; irqhandler - hardware IRQ handler routine
  2049. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2050. irqhandler:
  2051.         push    ax
  2052.         push    dx
  2053.         push    ds
  2054.         mov     ax,@data
  2055.         mov     ds,ax
  2056.  
  2057. ; send acknowledge to the PIC controller
  2058.  
  2059.         mov     al,20h
  2060.         cmp     [irqnum],08h
  2061.         jb      irqhandlerf0
  2062.         out     0A0h,al
  2063. irqhandlerf0:
  2064.         out     20h,al
  2065.  
  2066. ; send acknowledge to the DSP chip reading the 8 bit ack port (2XEh)
  2067.  
  2068.         mov     dx,[ioaddr]
  2069.         add     dx,0Eh
  2070.         in      al,dx
  2071.  
  2072. ; restart the 8 bit DMA mode playback transfer
  2073.  
  2074.         mov     al,14h
  2075.         call    sbwrite
  2076.         mov     al,0FFh
  2077.         call    sbwrite
  2078.         call    sbwrite
  2079.  
  2080.         pop     ds
  2081.         pop     dx
  2082.         pop     ax
  2083.         iret
  2084.  
  2085. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2086. ; irqtest - testing hardware IRQ handler routine
  2087. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2088. irqtest:
  2089.         push    dx                      ; common IRQ test handler code
  2090.         push    ds                      ; used for autodetection
  2091.         mov     dx,@data
  2092.         mov     ds,dx
  2093.         mov     [irqnum],al             ; save the IRQ level number
  2094.         mov     dx,[ioaddr]             ; send acknowledge signal to the
  2095.         add     dx,0Eh                  ; DSP reading the ack port (2XEh)
  2096.         in      al,dx
  2097.         mov     al,20h                  ; send acknowledge to the PIC
  2098.         cmp     [irqnum],08h            ; controllers
  2099.         jb      irqtestf0
  2100.         out     0A0h,al
  2101. irqtestf0:
  2102.         out     20h,al
  2103.         pop     ds
  2104.         pop     dx
  2105.         pop     ax
  2106.         iret
  2107.  
  2108.         irp     I,<2,3,5,7,10>          ; IRQ test handlers for each
  2109. irqtest&I:                              ; possible IRQ levels
  2110.         push    ax
  2111.         mov     ax,I
  2112.         jmp     irqtest
  2113.         endm
  2114.  
  2115. end
  2116.